home *** CD-ROM | disk | FTP | other *** search
- #include "TraceModule.h"
- #include <ToolUtils.h>
- #include <Errors.h>
- #include <Files.h>
- #include <Memory.h>>
- #include <Strings.h>
- #include <OSUtils.h>
- #include <Events.h>
- #include <Resources.h>
- #include <Devices.h>
- #include <types.h> // Mac types
- #include <Desk.h> /* for accRun */
- /***********************************************************************
- //
- // Tracks Driver
- // Copyright 1990, 1991 Orion Network Systems, Inc. All Rights Reserved.
- // Authors : Jim Flood, Brad Lowe
- //
- ************************************************************************/
-
-
- // clears circular buffer by setting start and end to the same place
- snum ClearTraceBuffer(TraceGlobals *globals)
- {
- register short result;
-
- if ( ! globals->fBufferEnabled)
- result = fnOpnErr; // "File not open" means trace is not enabled
- else
- {
- result = noErr;
- // when nextRead == nextWrite the buffer is empty..
- // Make it so
- globals->fNextReadPtr = globals->fBuffStartPtr;
- globals->fNextWritePtr = globals->fBuffStartPtr;
- }
- return(result);
- }
-
- // Each write to the file opens, writes and closes the file. This function
- // closes the output file.
- snum CloseTraceFile(TraceGlobals *globals)
- {
- register snum result;
- if ( ! globals->fFileIsOpen)
- result = fnOpnErr; // "File not open" Error -38
- else
- {
- // Close the file and flush the volume.
- // Set fFileIsOpen to false
-
-
- result = FSClose(globals->fFileRefNum);
- if (result == noErr) /* This would be is very odd if !true... */
- {
- globals->fFileIsOpen = false;
- result = FlushVol(nil, globals->fVRefNum);
- }
- // (void) SetFLock(globals->fTraceFileName, globals->fVRefNum);
- }
- return(result);
-
- }
-
- // Copy a mask. A mask would be either a break or a TracePoints mask.
- void DoCopyMask(MaskType src,MaskType dst)
- {
- BlockMove((Ptr)src,(Ptr)dst,sizeof(MaskType));
- }
-
-
- snum DisableTraceBuffer(TraceGlobals *globals)
- {
- register short result;
-
- if ( ! globals->fBufferEnabled)
- result = fnOpnErr; // "File not open" means trace is not enabled
- else
- {
- result = noErr;
- globals->fBufferEnabled = false;
- DisposPtr(globals->fBuffStartPtr);
- }
-
- return(result);
-
- }
-
- snum DisableTraceFile(TraceGlobals *globals)
- {
- register snum result;
-
- if ( ! globals->fFileEnabled)
- result = volOffLinErr; // "volume offline" means already disabled
- else
- {
- globals->fFileEnabled = false;
- // (void) RstFLock(globals->fTraceFileName, globals->fVRefNum);
- result = noErr;
- }
-
- return(result);
-
- }
-
- snum EnableTraceBuffer(TraceGlobals *globals, TraceParamBlock *paramPtr)
- {
- register short result;
- register Ptr bufferPtr;
- register lhex traceBuffSize;
- register shex maxRecordSize;
-
- if (globals->fBufferEnabled)
- result = fBsyErr; // "File is busy" means trace already enabled -47
- else
- {
- // Make sure the buffer size is even:
-
- traceBuffSize = paramPtr->u.enable.traceBuffSize;
- if (traceBuffSize & 1)
- traceBuffSize--;
-
- // Allocate the trace buffer (on the System Heap)
-
- bufferPtr = NewPtrSys(traceBuffSize);
-
- if (bufferPtr == nil)
- {
- result = MemError();
- }
-
- else
- {
-
- result = noErr;
-
- globals->fBufferEnabled = true;
- globals->fLockedOutFlag = false; // reset locked-out flag
-
- // initialize buffer control fields :
-
- globals->fTraceBuffSize = traceBuffSize;
- globals->fTraceBuffSizeIndex = paramPtr->u.enable.traceBuffSizeIndex;
- globals->fBuffStartPtr = bufferPtr;
- globals->fBuffEndPtr = bufferPtr + (traceBuffSize - 1);
- globals->fNextReadPtr = bufferPtr;
- globals->fNextWritePtr = bufferPtr;
-
- // Maximum size data record must leave room for at least one
- // Lost-Data record and one extra free byte in the buffer
-
- maxRecordSize = (traceBuffSize - sizeof(NewRecordTemplate)) - 1;
- globals->fMaxRecordSize = maxRecordSize;
-
- }
- }
-
- return(result);
-
- }
- snum SetTraceFileName(TraceGlobals *globals, TraceParamBlock *paramPtr)
- {
- register snum result;
- register Ptr fileName;
- register chex strlen; // unsigned!
- FInfo finderInfo;
- long fileLength = 0;
-
- //saveTypeHandle hSave;
- //short PrefsResRefNum;
-
- (void) CloseTraceFile(globals); /* Close out any old file... */
- // (void) RstFLock(globals->fTraceFileName,globals->fVRefNum); /* And let them trash it */
- fileName = (Ptr) paramPtr->u.enableFile.fileName;
- result = noErr;
-
- if (globals->fFileEnabled && 0 ) // NO LONGER APPLIES
- result = volOnLinErr; // "volume already online" means already enabled
-
- else if (fileName == nil)
- result = bdNamErr; // "Bad file name"
- else
- {
-
- // Volume refnum is passed also:
-
- globals->fVRefNum = paramPtr->u.enableFile.vRefNum;
-
- // (Truncate file name if too long)
-
- strlen = *fileName + 1;
- if (strlen > sizeof(globals->fTraceFileName))
- strlen = sizeof(globals->fTraceFileName);
-
- // Copy the file name:
-
- BlockMove(fileName, globals->fTraceFileName, strlen);
- globals->fTraceFileName[0] = strlen - 1; // (in case we truncated it)
-
- // Check if the file exists, and if it has the right Finder info..
- // If it doesn't exist, then create it.
-
- result = GetFInfo(globals->fTraceFileName, globals->fVRefNum, &finderInfo);
-
- if (result == fnfErr) // Doesnt exist, create a new one...
- {
- result = Create(fileName, globals->fVRefNum, globals->fMyCreator, globals->fMyFileType);
- }
- else
- if (result == noErr)
- {
- // Check file type and creator (it must be ours):
- if ( (finderInfo.fdType != globals->fMyFileType) ||
- (finderInfo.fdCreator != globals->fMyCreator) )
- result = extFSErr; // "External file system"
- }
- }
-
- if (result == noErr)
- {
- (void) OpenTraceFile(globals);
- if (result == noErr)
- {
- (void) GetEOF(globals->fFileRefNum,&fileLength);
- }
- (void)CloseTraceFile(globals);
- globals->fFileEnabled = true;
- globals->fBytesWritten = fileLength;
- // (void) SetFLock(globals->fTraceFileName,globals->fVRefNum); // no trash
- }
- return(result);
- }
-
-
- snum GetBufferSpace(TraceGlobals *globals, shex amountOfSpace, Boolean *dataLost)
- {
- snum result;
- register shex recordSize;
- register lhex freeSpace;
- register Boolean dataWasLost;
- register lhex bufferSize;
- register Ptr nextRead;
- register Ptr nextWrite;
- register Ptr buffEnd;
-
- // This function attempts to clear the requested amount of space
- // in the circular buffer, throwing out older records if needed.
- // If data is thrown out, true is returned in 'Boolean *dataLost'.
- // If the amount requested exceeds the maximum allowed record size,
- // then the function returns -1 without touching the buffer.
- // (Of course if there is plenty of room available, then no older
- // records are lost.)
-
- if (amountOfSpace > globals->fMaxRecordSize)
- result = -1;
- else
- {
- result = 0;
- dataWasLost = false;
-
- // Move some values into register variables for optimization:
-
- nextRead = globals->fNextReadPtr;
- nextWrite = globals->fNextWritePtr;
- buffEnd = globals->fBuffEndPtr;
- bufferSize = globals->fTraceBuffSize;
-
- // Loop until we have our space...
-
- freeSpace = 0;
- while (amountOfSpace >= freeSpace)
- {
-
- // Calculate how much free space is in the buffer. If the read and write
- // pointers are equal, then the buffer is empty. If the write pointer is
- // lower than the read pointer, then the free space is between the pointers
- // (i.e. up until the read pointer is reached). If the write pointer is
- // above the read pointer, then the free space is from the write pointer to
- // the end of the buffer, then wrapping around from the start of the buffer
- // up to the read pointer (i.e. the space between the pointers contains
- // unread trace records).
-
- if (nextWrite == nextRead) // READ==WRITE means empty buffer
- freeSpace = bufferSize;
- else if (nextWrite < nextRead)
- freeSpace = nextRead - nextWrite;
- else
- freeSpace = bufferSize - (nextWrite - nextRead);
-
- // If not enough free space, toss the oldest record and try again:
-
- if (amountOfSpace >= freeSpace)
- {
-
- dataWasLost = true;
-
- // retrieve the LL field :
- // (2 byte length field always falls on even memory boundary)
-
- recordSize = *((shex *) nextRead);
-
- // Move the read pointer, wrapping to start of buffer is needed:
-
- nextRead += recordSize;
-
- if (nextRead > buffEnd)
- nextRead = globals->fBuffStartPtr + (nextRead - buffEnd) - 1;
-
- }
- }
-
- // Move register variable value back into globals in case it was modified:
-
- globals->fNextReadPtr = nextRead;
-
- // Return lost data indication:
-
- *dataLost = dataWasLost;
-
- }
-
- return(result);
-
- }
-
-
- /*
- ** Set our gloabal data masks to the new mask that we get from the CDEV...
- */
-
- snum GetMaskFromCDEV(TraceGlobals *globals, TraceParamBlock *paramPtr,short csCode)
- {
- if (csCode == kGetCdevBreakMask)
- DoCopyMask(paramPtr->u.mask.Mask,globals->fBreakMask);
- else // kGetCdevTraceMask by default
- DoCopyMask(paramPtr->u.mask.Mask,globals->fTraceMask);
- globals->fBreakOnceThenClear = paramPtr->u.mask.BreakOnce;
- return(noErr);
- }
-
-
- void GetNewRecord(TraceGlobals *globals, shex recordSize, Ptr *recordAddr,
- shex *splitSize, Ptr *secondAddr)
- {
- snum result;
- Boolean dataWasLost;
- NewRecordTemplate template; // Used to create a lost-data record
- register shex topSize;
- register shex secondPart;
- register Ptr buffStart;
- register Ptr buffEnd;
- register Ptr nextWrite;
- register Ptr nextRead;
-
- dataWasLost = false;
-
- // Get space for the new record:
- // To increase performance, always ask for enough room for the new record
- // plus a lost-data record. Although the extra room for the lost-data record
- // may be what causes a lost-data condition, in this case the buffer is almost
- // full anyway and we are bound to lose data soon anyway. In this implementation,
- // we will sacrifice the efficiency of the buffer size in favor of efficiency
- // of execution (after all, if we are letting the buffer run full without
- // retrieving any records, we will definitely want the efficiency).
- // NOTE: Currently, if GetBufferSpace returns an error, we don't do anything at all.
-
- result = GetBufferSpace(globals, recordSize + sizeof(NewRecordTemplate), &dataWasLost);
-
- if (result == 0)
- {
-
- // Move some values into register variables for optimization:
-
- nextWrite = globals->fNextWritePtr;
- nextRead = globals->fNextReadPtr;
- buffStart = globals->fBuffStartPtr;
- buffEnd = globals->fBuffEndPtr;
-
- // If data was lost while finding buffer space, then insert a lost-data record:
- // This record must be inserted as the next read (in front of all other records).
-
- if (dataWasLost)
- {
- template.length = sizeof(NewRecordTemplate);
- template.diagID = kLostDataRecord;
- template.partCode = 0;
- if (globals->fTimeStampType == 1)
- GetDateTime(&template.timeStamp); // Date and Time timestamp
- else
- template.timeStamp = TickCount(); // Ticks (1/60 sec) timestamp
- template.timeStampType = globals->fTimeStampType;
- template.formatID = 0x00;
-
- secondPart = nextRead - buffStart;
- if (secondPart >= sizeof(NewRecordTemplate))
- {
- // It will fit in one piece ahead of next read record:
- nextRead -= sizeof(NewRecordTemplate);
- BlockMove((Ptr) &template, nextRead, sizeof(NewRecordTemplate));
- }
- else
- {
- // The record must be split (wrap-around backwards):
- topSize = sizeof(NewRecordTemplate) - secondPart;
- nextRead = (buffEnd - topSize) + 1;
- BlockMove((Ptr) &template, nextRead, topSize);
- BlockMove(((Ptr) &template) + secondPart, buffStart, secondPart);
- }
-
- // Move the register copy back into the globals block:
-
- globals->fNextReadPtr = nextRead;
-
- }
-
- // Calculate the return values:
-
- *recordAddr = nextWrite; // this is where the new record goes
-
- topSize = (buffEnd - nextWrite) + 1;
- if (topSize >= recordSize)
- {
- *splitSize = recordSize; // If we can fit it all before reaching the end...
- *secondAddr = nil; // ... then there is no second part to the record
- secondPart = 0;
- }
- else
- {
- secondPart = recordSize - topSize;
- *splitSize = topSize; // If the record passes the end of the buffer...
- *secondAddr = buffStart; // ... then pass the address for the second part
- }
-
- // Fix up the next write pointer:
-
- nextWrite += recordSize;
- if (nextWrite > buffEnd)
- nextWrite = buffStart + secondPart;
-
- // Don't forget to move the register copy back into the globals block:
-
- globals->fNextWritePtr = nextWrite;
-
- }
-
- return;
-
- }
- snum GetTraceProc(TraceGlobals *globals, TraceParamBlock *paramPtr)
- {
-
- paramPtr->u.traceProc.traceProcPtr = (TraceProcPtr)TraceProc;
- paramPtr->u.traceProc.traceValue = (long) globals;
-
- return(noErr);
- }
-
- snum GetTraceStatus(TraceGlobals *globals, TraceParamBlock *paramPtr)
- {
- TraceStatusBlk *statusPtr;
- Ptr nextRead;
- Ptr nextWrite;
- long bytesBuffered;
- char *s, *t;
- short len;
- short i;
-
- statusPtr = paramPtr->u.getStatus.statusPtr;
-
- statusPtr->online = globals->fTraceOnline;
- statusPtr->bufferEnabled = globals->fBufferEnabled;
- statusPtr->fileEnabled = globals->fFileEnabled;
- statusPtr->autoWrite = globals->fAutomaticWrite;
-
- statusPtr->bufferSize = globals->fTraceBuffSize;
- statusPtr->bufferSizeIndex = globals->fTraceBuffSizeIndex;
- statusPtr->breakOnceThenClear = globals->fBreakOnceThenClear;
- statusPtr->DebugMarkUnset = globals->fDebugMarkUnset;
- statusPtr->TraceOnStartup = globals->fTraceOnStartup;
- if ( ! globals->fBufferEnabled)
- bytesBuffered = 0;
- else
- {
- nextRead = globals->fNextReadPtr;
- nextWrite = globals->fNextWritePtr;
- if (nextRead < nextWrite)
- bytesBuffered = nextWrite - nextRead;
- else if (nextRead > nextWrite)
- bytesBuffered = globals->fTraceBuffSize - (nextRead - nextWrite);
- else
- bytesBuffered = 0;
- }
- statusPtr->bytesBuffered = bytesBuffered;
-
- if ( ! globals->fFileEnabled)
- {
- statusPtr->bytesWritten = 0;
- statusPtr->fileVolume = 0;
- t = statusPtr->fileName;
- for (i = 0; i < sizeof(statusPtr->fileName); i++)
- *t++ = 0;
- }
- else
- {
- statusPtr->bytesWritten = globals->fBytesWritten;
- statusPtr->fileVolume = globals->fVRefNum;
- len = globals->fTraceFileName[0] + 1;
- s = globals->fTraceFileName;
- t = statusPtr->fileName;
- for (i = 0; i < len; i++)
- *t++ = *s++;
- for (i = len; i < sizeof(statusPtr->fileName); i++)
- *t++ = 0;
- }
-
- return(noErr);
-
- }
-
- /*
- This is called once by DRVR open... It inits the globals, and finds out the
- driver name that Trace will trace.
- */
-
- void InitTrace(TraceGlobals *globals)
- {
- globals->fCheckID = 'TRAC';
- globals->fMyCreator = 'BNNY';
- globals->fMyFileType = kPrefsOSType; // preference file type
-
- globals->fBuffStartPtr = nil;
- globals->fBuffEndPtr = nil;
- globals->fNextReadPtr = nil;
- globals->fNextWritePtr = nil;
-
- globals->fTraceLock = false;
- globals->fBufferEnabled = false;
- globals->fFileEnabled = false;
- globals->fTraceOnline = false;
- globals->fFileIsOpen = false;
- globals->fAutomaticWrite = false;
- globals->fLockedOutFlag = false;
-
- globals->fBytesWritten = 0;
- globals->fWriteErr = 0;
-
- globals->fDriversRefNum = 0;
-
- globals->fTimeStampType = 1; // Always use date/time for now
- globals->fBreakOnceThenClear = true;
-
- return;
- }
-
- snum OpenTraceFile(TraceGlobals *globals)
- {
- register snum result;
- register char *fileName;
- register short vRefNum;
-
- if (globals->fFileIsOpen)
- result = tmfoErr; // "too many files open" if a file is already open
- else
- {
- // (void) RstFLock(globals->fTraceFileName,globals->fVRefNum);
-
- fileName = globals->fTraceFileName;
- vRefNum = globals->fVRefNum;
-
- // Open the file - return an error if file is not found
- // (EnableTraceFile should have already created it)
-
- result = FSOpen(fileName, vRefNum, &(globals->fFileRefNum));
-
- // Set the file position to the end of the file.
-
- if (result == noErr)
- {
- (void) SetFPos(globals->fFileRefNum, fsFromLEOF, 0);
- globals->fFileIsOpen = 1;
- }
- }
-
- return(result);
-
- }
-
- /*
- ** Effectivly erases the data in an output file,
- ** without all the hassles of using finder
- */
- snum ResetEOF(TraceGlobals *globals)
- {
- register snum result;
- // If the trace file is enabled, then open the file,
- // and set the eof...
-
- if ( ! globals->fFileEnabled && 0) // Ignore this if for now..
- result = volOffLinErr; // "Volume not on-line"
- else
- {
- result = OpenTraceFile(globals);
- if (result == noErr)
- {
- // Set the EOF to the start of the file.
- (void) SetEOF(globals->fFileRefNum,0L); // ignore errors here
- (void) CloseTraceFile(globals); // ignore errors here
- (void) FlushVol(nil, globals->fVRefNum); // ignore errors here
- globals->fBytesWritten = 0L;
- }
- }
- return(result);
- }
-
-
- /**
- *** Driver to CDEV
- **/
-
- snum SendMaskToCdev(TraceGlobals *globals, TraceParamBlock *paramPtr,short csCode)
- {
-
- if (csCode == kSendCdevBreakMask)
- DoCopyMask(globals->fBreakMask,paramPtr->u.mask.Mask);
- else
- if (csCode == kSendCdevTraceMask)
- DoCopyMask(globals->fTraceMask,paramPtr->u.mask.Mask);
-
- globals->fDebugMarkUnset = false;
- paramPtr->u.mask.BreakOnce = globals->fBreakOnceThenClear; // Breakpoint method
- return(noErr);
- }
-
- snum SetTraceOffline(TraceGlobals *globals)
- {
- snum result;
- CntrlParam ctlPB;
-
- if ( ! globals->fTraceOnline)
- result = volOffLinErr; // "volume not on-line"
- else
- {
-
- // Issue PBControl to the target driver:
-
- ctlPB.ioCompletion = 0;
- ctlPB.ioCRefNum = globals->fDriversRefNum;
- ctlPB.csCode = kRemoveTrace;
-
- result = PBControl((ParamBlockRec *) &ctlPB, false); // not async
-
- if (result == noErr)
- globals->fTraceOnline = false;
- }
-
- return(result);
-
- }
-
-
- snum SetTraceOnline(TraceGlobals *globals, char *driverDotName)
- {
- snum result;
- CntrlParam ctlPB;
- short x;
- char lengthByte;
-
- if (globals->fTraceOnline)
- result = volOnLinErr; // "volume already online"
- else
- {
-
- // Find the refnum of the correct driver:
-
- if (globals->fTraceBuffSize == 0)
- result = aspBufTooSmall; // Buffer too small. May be uninitialized
- else
- result = OpenDriver(driverDotName, &(globals->fDriversRefNum));
-
- if (result == noErr)
- {
- lengthByte = *driverDotName;
- for (x=0;x<lengthByte + 1;x++)
- globals->fDriverPStrName[x] = *driverDotName++;
-
- // Issue PBControl to the target driver:
-
- ctlPB.ioCompletion = 0;
- ctlPB.ioCRefNum = globals->fDriversRefNum;
- ctlPB.csCode = kInstallTrace;
- *((ProcPtr *) &(ctlPB.csParam[0])) = (ProcPtr) StripAddress((Ptr) TraceProc);
- *((Ptr *) &(ctlPB.csParam[2])) = (Ptr) globals;
-
- result = PBControl((ParamBlockRec *) &ctlPB, false); // not async
-
- if (result == noErr)
- {
- globals->fTraceOnline = true;
- }
-
- } else
- {
- globals->fDriverPStrName[0] = 0;
- }
- }
- return(result);
- }
-
- OSErr TClose(CntrlParam *ctlPB, DCtlPtr dCtl)
- {
- #pragma unused (ctlPB,dCtl)
- return(closErr); // Not allowed to close this driver
- }
-
-
- OSErr TControl(CntrlParam *ctlPB, DCtlPtr dCtl)
- {
- register OSErr error;
- register short csCode;
- register TraceParamBlock *paramPtr;
- register TraceGlobals *globals;
-
- // The dCtlStorage field in the DCE entry contains our globals pointer
-
- globals = (TraceGlobals *) dCtl->dCtlStorage;
- csCode = ctlPB->csCode;
-
- // change accRun to DoPeriodicTime
-
- if (csCode == accRun)
- csCode = kDoPeriodicTime;
-
- // The TraceParamBlock is in csParam:
-
- paramPtr = (TraceParamBlock *) &(ctlPB->csParam);
-
- // Call the Tracks code.
-
- error = TraceEntry(globals, csCode, paramPtr, dCtl);
-
- return(error);
-
- }
-
-
- OSErr TOpen(CntrlParam *ctlPB, DCtlPtr dCtl)
- {
- #pragma unused (ctlPB)
- register OSErr error;
- register TraceGlobals *globals;
-
- // The dCtlStorage field in the DCE entry is used to keep a pointer
- // to the global memory block. This will be nil on the first Open call.
-
- error = noErr;
- globals = (TraceGlobals *) dCtl->dCtlStorage;
-
- if (globals == nil)
- {
- // Allocate global storage as a non-relocatable block on the System Heap...
-
- globals = (TraceGlobals *) NewPtrSysClear(sizeof(TraceGlobals));
-
- if (globals == nil)
- error = MemError();
- else
- {
-
- // Initialize the trace code:
-
- InitTrace(globals);
-
- // Save a pointer to the globals in the DCE:
-
- dCtl->dCtlStorage = (Handle) globals;
-
- }
- }
-
- return(error);
-
- }
-
-
- OSErr TPrime(CntrlParam *ctlPB, DCtlPtr dCtl)
- {
- #pragma unused (ctlPB, dCtl)
- return(readErr);
- }
-
- OSErr TStatus(CntrlParam *ctlPB, DCtlPtr dCtl) {
- register OSErr error;
- register short csCode;
- register TraceParamBlock *paramPtr;
- register TraceGlobals *globals;
-
- // The dCtlStorage field in the DCE entry contains our globals pointer
-
- globals = (TraceGlobals *) dCtl->dCtlStorage;
- csCode = ctlPB->csCode;
-
- // The TraceParamBlock is returned in csParam:
-
- paramPtr = (TraceParamBlock *) &(ctlPB->csParam);
-
- error = TraceEntry(globals, csCode, paramPtr, dCtl);
-
- return(error);
-
- }
-
-
- void HandleTraceData(TraceGlobals *globals, char diagID, char partCode,
- char formatID, long data1, long data2, long data3);
-
- BlockAppend(Ptr sourcePtr, SafeMemBlock *MemBlock, long requestSize)
- {
- register long sizeLeft;
- register short result = 0;
-
- sizeLeft = (long) (MemBlock->End - MemBlock->Mark);
-
- if (sizeLeft-10 < requestSize)
- {
- requestSize = sizeLeft -1;
- result = memSCErr; // memory size check...
- }
-
- BlockMove(sourcePtr,MemBlock->Mark, requestSize);
- MemBlock->Mark += requestSize;
- return result;
- }
-
- /* This is the entry point for Trace calls from the target driver.
- ** This routine is not called from the driver-- it is called by the target driver.
- ** It can access this driver's globals because the target driver passes them in.
- */
- pascal void TraceProc(long refcon, char diagID, char partCode,
- char formatID, long data1, long data2, long data3)
- {
- register TraceGlobals *globals;
- register Boolean okLocked;
- register Boolean BreakOnExit = false;
-
- globals = (TraceGlobals *)refcon; // set up driver globals
-
- if (diagID < 128) // vaild diagID's range from 0 to 127...
- {
- // Check to see if there should be a break on exit (breakpoint was set).
- BreakOnExit = BitTst((Ptr)globals->fBreakMask,(long)diagID);
-
-
- // Check to see the information passed should be logged.
- if (BitTst((Ptr)globals->fTraceMask, (long)diagID))
- {
- // The trace point was set- check to see if the buffer exists and is ready.
- if (globals->fBufferEnabled) // There is a buffer to write to
- {
- okLocked = UTLock(&(globals->fTraceLock)); // test and set flag
-
- if (!okLocked) // If this trace request was locked out, then set locked-out flag
- globals->fLockedOutFlag = true; // one tracing request interrupted another
- else
- HandleTraceData(globals, diagID, partCode, formatID, data1, data2, data3);
- }
-
- }
- }
-
- // Handle the breakpoint, if any.
- if (BreakOnExit)
- {
- if (globals->fBreakOnceThenClear)
- {
- BitClr((Ptr)globals->fBreakMask,(long)diagID);
- globals->fDebugMarkUnset = true; // Signal cdev that debug mark was turned off
- DebugStr("\pTracks User Breakpoint (Once)");
- }
- else
- DebugStr("\pTracks User Breakpoint");
- }
- return;
- }
- // Dispatch incoming messages from control and status calls.
- pascal short TraceEntry(TraceGlobals *globals, short csCode, TraceParamBlock *paramPtr, DCtlPtr dCtl)
- {
- register short result;
- AutoTraceRec *atr;
-
- result = noErr;
-
- globals->fTraceLock = true;
-
- switch (csCode)
- {
-
- case kSetTraceOnline:
-
- result = SetTraceOnline(globals, (char *)paramPtr); /* The name of the target driver is in paramPtr (a pascal string) */
- break;
-
- case kSetTraceOffline:
- result = SetTraceOffline(globals);
- break;
-
- /**** NO LONGER USED
- case kTraceRead:
- result = ReadTrace(globals, paramPtr);
- break;
- ****/
-
- case kAutoTrace:
- atr = (AutoTraceRec *) paramPtr;
- TraceProc((long)globals, atr->diagID, atr->partCode, atr->formatID, atr->data1, atr->data2, atr->data3);
-
- break;
-
-
- case kEnableTraceBuffer:
- result = EnableTraceBuffer(globals, paramPtr);
- break;
-
- case kDisableTraceBuffer:
- result = DisableTraceBuffer(globals);
- break;
-
- case kSetTraceFileName:
- result = SetTraceFileName(globals, paramPtr);
- break;
-
- case kDisableTraceFile:
- result = DisableTraceFile(globals);
- break;
-
- case kWriteTraceBuffer:
- result = WriteTraceBuffer(globals);
- break;
-
- case kSetAutoWriteOn:
- globals->fAutomaticWrite = true;
- BitSet((Ptr) &dCtl->dCtlFlags, 2); /* set bit 5/dNeedTime bit.IM I-471*/
- break;
-
- case kSetAutoWriteOff:
- globals->fAutomaticWrite = false;
- BitClr((Ptr) &dCtl->dCtlFlags, 2); /* Clear bit 5/dNeedTime bit. */
- break;
-
- case kDoPeriodicTime:
- if ( (globals->fBufferEnabled) &&
- (globals->fFileEnabled) &&
- (globals->fAutomaticWrite) )
- result = WriteTraceBuffer(globals);
- break;
-
- case kGetTraceStatus:
- result = GetTraceStatus(globals, paramPtr);
- break;
-
- case kGetTraceProc:
- result = GetTraceProc(globals, paramPtr);
- break;
-
- case kSendCdevBreakMask:
- case kSendCdevTraceMask:
- result = SendMaskToCdev(globals,paramPtr,csCode);
- break;
- case kGetCdevBreakMask:
- case kGetCdevTraceMask:
- result = GetMaskFromCDEV(globals,paramPtr,csCode);
- break;
- case kResetEOF: // Reset the Trace.outfile to zero bytes in length
- result = ResetEOF(globals);
- break;
-
- case kClearTraceBuffer: // Clear the buffer-
- result = ClearTraceBuffer(globals);
- break;
-
- case kStartedFromInit:
- globals->fTraceOnStartup = (Boolean)paramPtr;
- break;
- default:
- result = controlErr; /* -17 */
- break;
-
- }
-
- globals->fTraceLock = false;
- return(result);
-
- }
-
- void HandleTraceData(TraceGlobals *globals, char diagID, char partCode, char formatID, long data1, long data2, long data3)
- {
- NewRecordTemplate template;
- register shex dataSize;
- shex recordSize;
- Ptr recordAddr; /* Address of new record */
- shex splitSize; /* Size of first part of record */
- Ptr secondAddr; /* Address of second part of record */
- Ptr copyTo;
- shex secondSize;
- Boolean padByte; /* true if pad byte is needed for even length */
- short procNameLen,callbyNameLen;
- chex LengthOfStackData;
- Ptr procNamePtr,callbyNamePtr,StackDataPtr;
- char SPBuffer[600];
- SafeMemBlock Mem; // To append data onto a hunk of memory...
- chex temp;
- register chex *bytePtr;
- register Ptr dataPtr;
- register short err;
-
- // Set up Append Buffer--
-
- Mem.Begin = SPBuffer;
- Mem.Mark = Mem.Begin; // Start appending at the beginning
- Mem.End = Mem.Begin + sizeof(SPBuffer);
- // Determine size needed for new trace record
-
- switch (formatID)
- {
-
- case 0x01: /* Stack Peek */
- // Call of StackPeek-- We are at level 2 (level 1 is TraceProc... level 0 is calling function... )
-
-
- StackPeek(3,
- &procNamePtr, &procNameLen,
- &callbyNamePtr, &callbyNameLen,
- &StackDataPtr);
-
- // BlockAppend is like BlockMove (source,dest, numBytes)
- // But it keeps track of the end of the buffer so it can Append (hence the name)
-
-
- // Stackpeek data is stored as follows:
- // stack data length byte (n) + stack data (n bytes)
- // Pascal string containing length of function name
- // Pascal string of previous caller...
-
- LengthOfStackData = 32; // How much stack data to dump... this is for stackpeek
-
- BlockAppend((Ptr)&LengthOfStackData, &Mem, (long)1); // Insert length byte
-
- BlockAppend(StackDataPtr,&Mem,(long) LengthOfStackData ); // Append stackdata
-
- temp = (chex) procNameLen; // cast to char
- BlockAppend( (Ptr) &temp,&Mem, 1L); // Insert Length byte
- BlockAppend(procNamePtr,&Mem,(lhex)procNameLen); // And the data
-
- temp = (chex) callbyNameLen;
- BlockAppend((Ptr)&temp, &Mem, 1L); // Insert Length byte
- err = BlockAppend(callbyNamePtr, &Mem, (lhex)callbyNameLen); // Insert the data from stackpeek
-
- dataSize = (shex) (Mem.Mark - Mem.Begin);
- dataPtr = (Ptr)Mem.Begin;
- break;
-
- case 0x02: /* Ptr to memory */
- dataPtr = (Ptr)data1;
- dataSize = (shex)data2;
- break;
-
- case 0x03: /* Pascal string */
- bytePtr = (chex *)data1; // point to the pascal string length byte
- dataPtr = (Ptr) data1;
- dataSize = (shex) (*bytePtr) + 1; /* Pascal string length byte */
- break;
-
- case 0x04: /* Long value */
- dataSize = 4;
- dataPtr = (Ptr) &data2; /* dummy up dataPtr */
- break;
-
- case 0x05: /* pascal and long value */
-
- // data1 = Pascal String, data2 = long value, data3 ignored.
- BlockAppend((Ptr)&data2, &Mem, 4L); // And the data
-
- bytePtr = (chex *)data1; // point to the pascal string length byte
- BlockAppend((Ptr)data1, &Mem, (long)(*bytePtr)+1); // Insert the pstring
-
- dataSize = (shex) Mem.Mark - Mem.Begin;
- dataPtr = (Ptr)Mem.Begin;
- break;
-
- case 0x06: // Length of data, Data, Pstr [data type name]
- // data1 = DataPtr, data2 = DataLen, data3 = Pstr
-
- BlockAppend((Ptr)&data2, &Mem, 4L); // The length of data (a long)
-
- BlockAppend((Ptr)data1, &Mem, data2); // Insert the data
-
- bytePtr = (chex *) data3; // point to the pascal string length byte
- BlockAppend((Ptr)data3, &Mem, (long) *bytePtr+1); // Insert the pstring
-
- dataSize = (shex) (Mem.Mark - Mem.Begin);
- dataPtr = (Ptr)Mem.Begin;
- break;
-
-
- // values 07 through 128 are reserved for Orion Network systems.
- // values 129 are free for public use.
-
- default:
- // DebugStr("\pTracks: Unknown Format ID");
- dataSize = 0;
- dataPtr = 0; // Should make this some kind of error record...
- break;
-
- }
- if (dataSize > 1024)
- {
- dataSize = 1024; /* truncate to 1024 max */
- }
- recordSize = dataSize + sizeof(template);
-
- // Make sure that the size is even:
-
- if (recordSize & 1) // If Odd
- {
- padByte = true;
- recordSize++;
- }
- else // Its even...
- padByte = false;
-
- // Get a new record to copy the data into
-
- GetNewRecord(globals, recordSize, &recordAddr, &splitSize, &secondAddr);
-
- // Fill in the record template
- // (Fill in the timestamps after calling GetNewRecord() in case
- // a lost-data record was inserted by GetNewRecord() - this keeps
- // our timestamps later than its timestamps.)
-
- template.length = recordSize;
- template.diagID = diagID;
- template.partCode = partCode;
- template.timeStampType = globals->fTimeStampType;
-
- if (globals->fTimeStampType == 1)
- GetDateTime(&template.timeStamp); // Date and Time timestamp
- else
- template.timeStamp = TickCount(); // Ticks (1/60 sec) timestamp
- template.formatID = formatID;
-
- // Where TTTTTTTT is the template, and DDDDDDDDDDDD is the data, then
- // recordAddr, splitSize, and secondAddr represent one of these:
- // <----------- BUFFER ----------->
- // (1) ----TTTTTTTTDDDDDDDDDDDD--------
- // (2) DDDDDDDDDDDD------------TTTTTTTT
- // (3) DDDDDDDD------------TTTTTTTTDDDD
- // (4) TTTTDDDDDDDDDDDD------------TTTT
- // In all cases, recordAddr points to the start of the template area.
- // In case (1), secondAddr is nil, and in cases (2), (3), and (4) secondAddr
- // points to the start of the buffer.
- // In case (1), splitSize is the size of the entire record. In case (2),
- // splitSize is exactly the size of the template. In case (3), splitSize is
- // larger than the template size but smaller than the record size. In case
- // (4), splitSize is smaller than the template size.
-
- copyTo = recordAddr;
- if (copyTo != nil)
- {
-
- // First copy the template:
-
- if (splitSize < sizeof(template))
- {
- BlockMove((Ptr) &template, copyTo, splitSize);
- copyTo = secondAddr;
- secondAddr = nil; // there is no longer a second part
- secondSize = sizeof(template) - splitSize;
- BlockMove((Ptr) &template, copyTo, secondSize);
- copyTo += secondSize;
- splitSize = dataSize;
- }
- else
- {
- BlockMove((Ptr) &template, copyTo, sizeof(template));
- copyTo += sizeof(template);
- splitSize -= sizeof(template);
- if (splitSize == 0)
- {
- copyTo = secondAddr;
- secondAddr = nil;
- splitSize = dataSize;
- }
- }
-
- // Then copy the data:
-
- if (dataSize > 0)
- {
- if (splitSize < dataSize)
- {
- BlockMove(dataPtr, copyTo, splitSize);
- copyTo = secondAddr;
- secondSize = dataSize - splitSize;
- BlockMove(dataPtr + splitSize, copyTo, secondSize);
- copyTo += secondSize;
- }
- else
- {
- BlockMove(dataPtr, copyTo, dataSize);
- copyTo += dataSize;
- }
-
- // Clear the pad byte if there is one
- // (Since buffer size is always even, we are guaranteed not to write
- // past the end of the buffer for this last byte since it is only
- // written following an odd data length.)
-
- if (padByte)
- *copyTo = 0;
- }
-
- }
-
- // Unlock the trace code...
-
- globals->fTraceLock = false;
-
- }
-
-
- snum WriteTraceBuffer(TraceGlobals *globals)
- {
- register snum result;
- long bytesToWrite;
- register Ptr nextRead;
- register Ptr nextWrite;
- register Ptr buffEnd;
- register Ptr buffStart;
- lhex firstPart;
- lhex secondPart;
-
- // If the buffer and trace file are both enabled, then open the file,
- // write the trace buffer, and close the file:
-
- if ( ! globals->fBufferEnabled)
- result = nsvErr; // "Specified volume doesn't exist"
- else if ( ! globals->fFileEnabled)
- result = volOffLinErr; // "Volume not on-line"
- else
- {
- // Move some globals into register variables for optimization:
-
- nextRead = globals->fNextReadPtr;
- nextWrite = globals->fNextWritePtr;
- buffEnd = globals->fBuffEndPtr;
- buffStart = globals->fBuffStartPtr;
-
- // When nextRead == nextWrite, the buffer is empty. Otherwise,
- // when nextRead < nextWrite, the data is in one piece in the middle of
- // the buffer, and when nextRead > nextWrite the data is in two pieces
- // (like the cross-section of a donut), from nextRead to the end of the buffer,
- // then wrapping around from the beginning of the buffer to nextWrite.
-
- if (nextRead == nextWrite)
- result = noErr; // empty buffer - nothing to write
- else
- {
-
- // Open the file - return an error if file is not found
- // (EnableTraceFile should have already created it)
-
- // result = FSOpen(globals->fTraceFileName, globals->fVRefNum, &refNum);
- /****&(globals->fFileRefNum));--- NO LONGER USED *****/
-
- result = OpenTraceFile(globals);
-
- if (result == noErr)
- {
-
-
- // Set the file position to the end of the file.
- (void) SetFPos(globals->fFileRefNum, fsFromLEOF, 0);
-
- if (nextRead < nextWrite)
- {
- firstPart = nextWrite - nextRead; // size of entire piece of data
- secondPart = 0;
- }
- else
- {
- firstPart = (buffEnd - nextRead) + 1; // size of first part of data
- secondPart = nextWrite - buffStart; // size of second part of data
- }
-
- // The first part always starts at nextRead...
-
- bytesToWrite = firstPart;
- result = FSWrite(globals->fFileRefNum, &bytesToWrite, nextRead);
- globals->fBytesWritten += bytesToWrite;
-
- // If there is a second part, it always starts at buffStart...
-
- if ((result == noErr) && (secondPart != 0))
- {
- bytesToWrite = secondPart;
- result = FSWrite(globals->fFileRefNum, &bytesToWrite, buffStart);
- globals->fBytesWritten += bytesToWrite;
- }
-
- if (result != noErr)
- globals->fWriteErr = result; // always save last write error
-
- // Clear the buffer...
-
- globals->fNextReadPtr = nextWrite;
-
- // Close the file and flush the volume:
- (void) CloseTraceFile(globals); // ignore errors here
-
- }
-
- }
-
- }
-
-
- return(result);
-
- }
- /*
- * StackPeek.c
- *
- */
-
-
-
- /* StackPeek seaches n levels deep into the stack to find the calling procedure
- ** and its parameters. Copyright 1990-1991 Orion Network Systems, All rights reserved.
- */
-
- #define kJMPA0Instr 0x4ED0 /* MC68000 JMP(A0) instruction format */
- #define kRTSInstr 0x4E75 /* MC68000 RTS instruction format */
- #define kRTDInstr 0x4E74 /* MC68000 RTD instruction format (first word) */
-
- /* UTPeek is a function which returns the current value of register A6 */
- pascal long *UTPeekA6();
-
- void StackPeek(short level, Ptr *procNamePtrLoc, short *procNameLenLoc,
- Ptr *callbyNamePtrLoc, short *callbyNameLenLoc, Ptr *stackPtrLoc)
- {
- long *framePtr; /* used to point into the stack */
- long *procFramePtr; /* used to point into the stack */
- register long *stackedArgsPtr; /* used to point into the stack */
- short *procInstrPtr; /* used to point at program instructions */
- short *callbyInstrPtr; /* used to point at program instructions */
- register unsigned char *procSymPtr;
- register unsigned char *callbySymPtr;
- register short procSymLen;
- register short callbySymLen;
- int i;
-
-
- /*
- * Register A6 contains the current frame pointer, which points into the
- * stack at the previous frame pointer which belongs to the calling function.
- */
-
- framePtr = UTPeekA6();
- procFramePtr = (long *) *framePtr;
-
-
- /*
- * When 'level' is greater than zero, we go back on the stack to find
- * the stack information for an earlier function (in the calling chain).
- * Follow the frame pointer chain backwards, until we get to framePtr
- * for the function which was CALLED by the desired target function,
- * and this will get us procFramePtr for the target function.
- */
-
- for (i = 0; i < level; i++)
- {
- framePtr = procFramePtr;
- procFramePtr = (long *) *framePtr;
- }
-
-
- /*
- * The frame pointer for the function which was called by the target
- * function points into the stack just above the return address which
- * returns INTO the target function.
- * The frame pointer which was used by the target function points
- * further down into the stack just above the return address of the
- * function which the target function was called by. Just below this
- * return address (of our target's caller) are the arguments to the
- * target function (pushed by our target's caller).
- */
-
- procInstrPtr = (short *) *(framePtr + 1);
- callbyInstrPtr = (short *) *(procFramePtr + 1);
- stackedArgsPtr = procFramePtr;
-
-
- /*
- * With the two instruction pointers, scan the actual code instructions
- * to find the Macsbug symbol for the function (look for RTS, JMP(A0),
- * or RTD --- the Macsbug 6.1 documentation lists RTD as a possibility)...
- */
-
- while ( (*procInstrPtr != kRTSInstr) &&
- (*procInstrPtr != kJMPA0Instr) &&
- (*procInstrPtr != kRTDInstr) )
- procInstrPtr++;
-
- procSymPtr = (unsigned char *) (procInstrPtr + 1);
- procSymLen = *procSymPtr++ & 0x7f;
-
- if (procSymLen == 0)
- {
- /* when variable symbol length is greater than 0x1f */
- procSymLen = *procSymPtr++;
- }
- else if (procSymLen > 0x1f)
- {
- /* fixed length symbol if first byte in the range of 0x20 through 0x7f */
- /* (with or without high bit set) */
- if (*procSymPtr & 0x80) /* 16 byte symbol if high bit set in 2nd byte */
- procSymLen = 16;
- else
- procSymLen = 8;
- procSymPtr--;
- }
-
-
- while ( (*callbyInstrPtr != kRTSInstr) &&
- (*callbyInstrPtr != kJMPA0Instr) &&
- (*callbyInstrPtr != kRTDInstr) )
- callbyInstrPtr++;
-
- callbySymPtr = (unsigned char *) (callbyInstrPtr + 1);
- callbySymLen = *callbySymPtr++ & 0x7f;
-
- if (callbySymLen == 0)
- {
- /* when variable symbol length is greater than 0x1f */
- callbySymLen = *callbySymPtr++;
- }
- else if (callbySymLen > 0x1f)
- {
- /* fixed length symbol if in the range of 0x20 through 0x7f */
- if (*callbySymPtr & 0x80)
- callbySymLen = 16;
- else
- callbySymLen = 8;
- callbySymPtr--;
- }
-
-
- /* return values */
-
- *procNamePtrLoc = (Ptr) procSymPtr;
- *procNameLenLoc = procSymLen;
- *callbyNamePtrLoc = (Ptr) callbySymPtr;
- *callbyNameLenLoc = callbySymLen;
- *stackPtrLoc = (Ptr) stackedArgsPtr;
-
- return;
-
- }
-
-